package com.iwhalecloud.bss.kite.cucc.order.operate;

import com.iwhalecloud.bss.kite.common.constant.ErrorConsts;
import com.iwhalecloud.bss.kite.common.constant.TableConsts;
import com.iwhalecloud.bss.kite.common.util.KiteBeanUtils;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.cucc.order.dto.OrderOperateDTO;
import com.iwhalecloud.bss.kite.cucc.order.save.SaveHandlerFactory;
import com.iwhalecloud.bss.kite.cucc.order.save.ISaveHandler;
import com.iwhalecloud.bss.kite.cucc.order.util.AcceptUtils;
import com.iwhalecloud.bss.kite.cucc.order.util.TableUtils;
import com.iwhalecloud.bss.kite.dataservice.entity.AcctItem;
import com.iwhalecloud.bss.kite.dataservice.entity.AcctItemHis;
import com.iwhalecloud.bss.kite.dataservice.entity.CustomerOrder;
import com.iwhalecloud.bss.kite.dataservice.entity.OrderAttr;
import com.iwhalecloud.bss.kite.dataservice.entity.OrderContactInfo;
import com.iwhalecloud.bss.kite.dataservice.entity.OrderHandler;
import com.iwhalecloud.bss.kite.dataservice.entity.OrderItem;
import com.iwhalecloud.bss.kite.dataservice.entity.OrderItemAttr;
import com.iwhalecloud.bss.kite.dataservice.entity.OrderItemRel;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.IInst;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.OfferInst;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.ProdInst;
import com.iwhalecloud.bss.kite.dataservice.entity.order.DevStaffInfo;
import com.iwhalecloud.bss.kite.dataservice.entity.order.OrderDeposit;
import com.iwhalecloud.bss.kite.dataservice.entity.order.OrderItemChange;
import com.iwhalecloud.bss.kite.dataservice.enums.TableConfig;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.order.client.api.operate.ISaveOrderService;
import com.iwhalecloud.bss.kite.order.client.dto.InstContainer;
import com.iwhalecloud.bss.kite.order.client.dto.OrderContainer;
import com.iwhalecloud.bss.kite.order.client.dto.OrderRequest;
import com.iwhalecloud.bss.kite.order.client.proxy.OrderContainerProxy;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
public class SaveOrderService implements ISaveOrderService {

    @Override
    public void save(OrderRequest orderRequest) {
        OrderOperateDTO orderOperate = toOrderOperate(orderRequest);
        operate(orderOperate);
    }

    /**
     * 把订单请求对象转换成实例&订单入库操作对象
     * @param orderRequest
     * @return
     */
    protected OrderOperateDTO toOrderOperate(OrderRequest orderRequest) {
        OrderOperateDTO orderOperate = new OrderOperateDTO();
        InstContainer.ofRequest(orderRequest).listInsts().forEach(inst -> {
            String className = inst.getClass().getSimpleName();
            TableConsts tableConsts = EnumUtils.getEnum(TableConsts.class, className);
            if (Objects.isNull(tableConsts)) {
                ErrorConsts.BUSI_COMMON_ERROR.throwOut("no table consts [TableConsts." + className + "]");
            }

            String tableName = tableConsts.getTableName();
            if (StringUtils.isNotBlank(inst.getNewOwnerCustId())
                && !KiteStringUtils.equals(inst.getOwnerCustId(), inst.getNewOwnerCustId())) {
                // 过户
                orderOperate.getTransferInstMap().computeIfAbsent(tableName, key -> new ArrayList<>()).add(inst);
            }
            else if (AcceptUtils.isAddInst(inst)) {
                // actionType == A && isBlank(newActionType)
                orderOperate.getInsertInstMap().computeIfAbsent(tableName, key -> new ArrayList<>()).add(inst);
            }
            else if (canUpdate(orderRequest, inst)) {
                // (actionType == A && newActionType == M) || actionType == M
                orderOperate.getUpdateInstMap().computeIfAbsent(tableName, key -> new ArrayList<>()).add(inst);
            }
            else if (Objects.equals(ActionType.D.name(), inst.getActionType())) {
                TableConfig tableConfig = EnumUtils.getEnum(TableConfig.class, StringUtils.upperCase(tableName));
                if (Objects.isNull(tableConfig)) {
                    ErrorConsts.BUSI_COMMON_ERROR.throwOut("no table config [TableConfig." + tableName + "]");
                }

                try {
                    // 删除只是把actionType改为D，竣工时才删除归档
                    String idField = tableConfig.getIdField();
                    IInst newInst = inst.getClass().newInstance();
                    KiteBeanUtils.setValueByName(newInst, idField, KiteBeanUtils.getValueByName(inst, idField));
                    newInst.setOwnerCustId(inst.getOwnerCustId());
                    newInst.setActionType(inst.getActionType());
                    orderOperate.getUpdateInstMapSelective().computeIfAbsent(tableName, key -> new ArrayList<>())
                        .add(newInst);

                    TableConfig extTableConfig = TableUtils.getExtTableConfig(tableName);
                    if (Objects.nonNull(extTableConfig)) {
                        String extIdField = extTableConfig.getIdField();
                        KiteBeanUtils.setValueByName(newInst, extIdField,
                            KiteBeanUtils.getValueByName(inst, extIdField));
                    }
                }
                catch (InstantiationException | IllegalAccessException e) {
                    ErrorConsts.SYSTEM_ERROR.throwOut(e);
                }

                TableConfig extTableConfig = TableUtils.getExtTableConfig(tableName);
                if (Objects.nonNull(extTableConfig)) {
                    try {
                        String extIdField = extTableConfig.getIdField();
                        Class<IInst> entityClass = extTableConfig.getEntityClass();
                        IInst newExtInst = entityClass.newInstance();
                        KiteBeanUtils.setValueByName(newExtInst, extIdField,
                            KiteBeanUtils.getValueByName(inst, extIdField));
                        newExtInst.setOwnerCustId(inst.getOwnerCustId());
                        newExtInst.setActionType(inst.getActionType());
                        orderOperate.getUpdateInstMapSelective()
                            .computeIfAbsent(extTableConfig.name(), key -> new ArrayList<>()).add(newExtInst);
                    }
                    catch (InstantiationException | IllegalAccessException e) {
                        ErrorConsts.SYSTEM_ERROR.throwOut(e);
                    }
                }
            }
        });

        CustomerOrder customerOrder = orderRequest.getOrderContainer().getCustomerOrder();
        if (Objects.nonNull(customerOrder)) {
            if (StringUtils.isNotBlank(customerOrder.getNewCustId())
                && !KiteStringUtils.equals(customerOrder.getCustId(), customerOrder.getNewCustId())) {
                orderOperate.getTransferCustomerOrders().add(customerOrder);

                // 联动修改所有关联表的custId
                String custOrderId = customerOrder.getCustOrderId();
                orderRequest.getOrderContainer().getOrderHandlerMap().getOrDefault(custOrderId, new ArrayList<>())
                    .forEach(orderHandler -> {
                        orderHandler.setCustId(customerOrder.getNewCustId());
                    });

                orderRequest.getOrderContainer().getOrderContactInfoMap().getOrDefault(custOrderId, new ArrayList<>())
                    .forEach(orderContactInfo -> {
                        orderContactInfo.setCustId(customerOrder.getNewCustId());
                    });
            }
            else if (Objects.equals(ActionType.A.name(), customerOrder.getActionType())) {
                orderOperate.getInsertCustomerOrders().add(customerOrder);
            }
            else if (Objects.equals(ActionType.M.name(), customerOrder.getActionType())) {
                orderOperate.getUpdateCustomerOrders().add(customerOrder);
            }
            else if (Objects.equals(ActionType.D.name(), customerOrder.getActionType())) {
                orderOperate.getDeleteCustomerOrders().add(customerOrder);
            }
        }

        OrderContainerProxy orderContainer = OrderContainer.ofRequest(orderRequest);
        orderContainer.listOrderAttrs().forEach(orderAttr -> {
            if (StringUtils.isNotBlank(orderAttr.getNewCustId())
                && !KiteStringUtils.equals(orderAttr.getCustId(), orderAttr.getNewCustId())) {
                orderOperate.getTransferOrderAttrs().add(orderAttr);
            }
            else if (Objects.equals(ActionType.A.name(), orderAttr.getActionType())) {
                orderOperate.getInsertOrderAttrs().add(orderAttr);
            }
            else if (Objects.equals(ActionType.M.name(), orderAttr.getActionType())) {
                orderOperate.getUpdateOrderAttrs().add(orderAttr);
            }
            else if (Objects.equals(ActionType.D.name(), orderAttr.getActionType())) {
                orderOperate.getDeleteOrderAttrs().add(orderAttr);
            }
        });

        orderContainer.listOrderItems().forEach(orderItem -> {
            if (StringUtils.isNotBlank(orderItem.getNewBelongCustId())
                && !KiteStringUtils.equals(orderItem.getBelongCustId(), orderItem.getNewBelongCustId())) {
                orderItem.setBelongCustId(orderItem.getNewBelongCustId());

                // 联动修改所有关联表的custId
                String orderItemId = orderItem.getOrderItemId();
                orderRequest.getOrderContainer().getOrderItemRelMap().forEach((orderItemRelId, orderItemRel) -> {
                    if (Objects.equals(orderItemId, orderItemRel.getOrderItemId())) {
                        orderItemRel.setCustId(orderItem.getBelongCustId());
                    }
                });

                orderRequest.getOrderContainer().getOrderItemAttrMap().getOrDefault(orderItemId, new ArrayList<>())
                    .forEach(orderItemAttr -> {
                        orderItemAttr.setCustId(orderItem.getBelongCustId());
                    });

                orderRequest.getOrderContainer().getOrderItemChangeMap().getOrDefault(orderItemId, new ArrayList<>())
                    .forEach(orderItemChange -> {
                        orderItemChange.setCustId(orderItem.getBelongCustId());
                    });

                orderRequest.getOrderContainer().getAcctItemMap().getOrDefault(orderItemId, new ArrayList<>())
                    .forEach(acctItem -> {
                        acctItem.setCustId(orderItem.getBelongCustId());
                    });

                orderRequest.getOrderContainer().getDevStaffInfoMap().getOrDefault(orderItemId, new ArrayList<>())
                    .forEach(devStaffInfo -> {
                        devStaffInfo.setCustId(orderItem.getBelongCustId());
                    });

                orderRequest.getOrderContainer().getOrderDepositMap().getOrDefault(orderItemId, new ArrayList<>())
                    .forEach(orderDeposit -> {
                        orderDeposit.setCustId(orderItem.getBelongCustId());
                    });
            }
        });

        orderOperate.getInsertOrderItems().addAll(orderContainer.listOrderItems());
        orderOperate.getInsertOrderItemRels().addAll(orderContainer.listOrderItemRels());
        orderOperate.getInsertOrderHandlers().addAll(orderContainer.listOrderHandlers());
        orderOperate.getInsertOrderContactInfos().addAll(orderContainer.listOrderContactInfos());
        orderOperate.getInsertOrderItemAttrs().addAll(orderContainer.listOrderItemAttrs());
        orderOperate.getInsertOrderItemChanges().addAll(orderContainer.listOrderItemChanges());
        orderOperate.getInsertAcctItems().addAll(orderContainer.listAcctItems());
        orderOperate.getInsertDevStaffInfos().addAll(orderContainer.listDevStaffInfos());
        orderOperate.getInsertOrderDeposits().addAll(orderContainer.listOrderDeposits());

        return orderOperate;
    }

    /**
     * 如果是销售品实例或者接入产品实例，actionType=M没有变动信息，不更新<br>
     * 例如改功能产品或改可选包，父级实例的actionType是M，但是没有其他属性的变动信息，不需要更新
     * @param orderRequest
     * @param inst
     * @return
     */
    protected boolean canUpdate(OrderRequest orderRequest, IInst inst) {
        if (Objects.isNull(inst)) {
            return false;
        }

        boolean canUpdate = AcceptUtils.isModifyInst(inst);
        String instId = "";
        String compInstId = "";
        if (inst instanceof OfferInst) {
            instId = ((OfferInst) inst).getOfferInstId();
            compInstId = ((OfferInst) inst).getCompInstId();
        }
        else if (inst instanceof ProdInst) {
            instId = ((ProdInst) inst).getProdInstId();
            compInstId = ((ProdInst) inst).getCompInstId();
        }

        if (StringUtils.isNotBlank(compInstId)) {
            String tableName = TableUtils.getTableName(inst.getClass());
            List<OrderItem> orderItems = OrderContainer.ofRequest(orderRequest).listOrderItemsByOfferInstId(compInstId);

            List<OrderItemChange> orderItemChanges = new ArrayList<>();
            for (OrderItem orderItem : orderItems) {
                orderItemChanges.addAll(OrderContainer.ofRequest(orderRequest)
                    .listOrderItemChangesByOrderItemId(orderItem.getOrderItemId(), tableName, instId));
            }

            if (CollectionUtils.isEmpty(orderItemChanges)) {
                canUpdate = false;
            }
        }

        return canUpdate;
    }

    /**
     * 入库操作
     * @param orderOperate
     */
    protected void operate(OrderOperateDTO orderOperate) {
        if (Objects.isNull(orderOperate)) {
            return;
        }

        insertInsts(orderOperate.getInsertInstMap());
        updateInsts(orderOperate.getUpdateInstMap());
        updateInstsSelective(orderOperate.getUpdateInstMapSelective());
        deleteInsts(orderOperate.getDeleteInstMap());
        transferInsts(orderOperate.getTransferInstMap());
        insertCustomerOrders(orderOperate.getInsertCustomerOrders());
        updateCustomerOrders(orderOperate.getUpdateCustomerOrders());
        updateCustomerOrdersSelective(orderOperate.getUpdateCustomerOrdersSelective());
        deleteCustomerOrders(orderOperate.getDeleteCustomerOrders());
        transferCustomerOrders(orderOperate.getTransferCustomerOrders());
        insertOrderItems(orderOperate.getInsertOrderItems());
        insertOrderItemRels(orderOperate.getInsertOrderItemRels());
        insertOrderAttrs(orderOperate.getInsertOrderAttrs());
        updateOrderAttrs(orderOperate.getUpdateOrderAttrs());
        deleteOrderAttrs(orderOperate.getDeleteOrderAttrs());
        transferOrderAttrs(orderOperate.getTransferOrderAttrs());
        insertOrderHandlers(orderOperate.getInsertOrderHandlers());
        insertOrderContactInfos(orderOperate.getInsertOrderContactInfos());
        insertOrderItemAttrs(orderOperate.getInsertOrderItemAttrs());
        insertOrderItemChanges(orderOperate.getInsertOrderItemChanges());
        insertAcctItems(orderOperate.getInsertAcctItems());
        insertDevStaffInfos(orderOperate.getInsertDevStaffInfos());
        insertOrderDeposits(orderOperate.getInsertOrderDeposits());
    }

    /**
     * 新增实例
     * @param instMap
     */
    protected void insertInsts(Map<String, List<IInst>> instMap) {
        if (MapUtils.isEmpty(instMap)) {
            return;
        }

        instMap.forEach((tableName, insts) -> {
            if (CollectionUtils.isEmpty(insts)) {
                return;
            }

            ISaveHandler<IInst> saveHandler = SaveHandlerFactory.getSaveHandler(insts.get(0).getClass());
            saveHandler.insert(insts, tableName);
        });
    }

    /**
     * 更新实例
     * @param instMap
     */
    protected void updateInsts(Map<String, List<IInst>> instMap) {
        if (MapUtils.isEmpty(instMap)) {
            return;
        }

        instMap.forEach((tableName, insts) -> {
            if (CollectionUtils.isEmpty(insts)) {
                return;
            }

            ISaveHandler<IInst> saveHandler = SaveHandlerFactory.getSaveHandler(insts.get(0).getClass());
            saveHandler.update(insts, tableName);
        });
    }

    /**
     * 更新实例(update不为null的值)
     * @param instMap
     */
    protected void updateInstsSelective(Map<String, List<IInst>> instMap) {
        if (MapUtils.isEmpty(instMap)) {
            return;
        }

        instMap.forEach((tableName, insts) -> {
            if (CollectionUtils.isEmpty(insts)) {
                return;
            }

            ISaveHandler<IInst> saveHandler = SaveHandlerFactory.getSaveHandler(insts.get(0).getClass());
            saveHandler.updateSelective(insts, tableName);
        });
    }

    /**
     * 删除实例
     * @param instMap
     */
    protected void deleteInsts(Map<String, List<IInst>> instMap) {
        if (MapUtils.isEmpty(instMap)) {
            return;
        }

        instMap.forEach((tableName, insts) -> {
            if (CollectionUtils.isEmpty(insts)) {
                return;
            }

            ISaveHandler<IInst> saveHandler = SaveHandlerFactory.getSaveHandler(insts.get(0).getClass());
            saveHandler.delete(insts, tableName);
        });
    }

    /**
     * 过户实例
     * @param instMap
     */
    protected void transferInsts(Map<String, List<IInst>> instMap) {
        if (MapUtils.isEmpty(instMap)) {
            return;
        }

        instMap.forEach((tableName, insts) -> {
            if (CollectionUtils.isEmpty(insts)) {
                return;
            }

            ISaveHandler<IInst> saveHandler = SaveHandlerFactory.getSaveHandler(insts.get(0).getClass());
            saveHandler.transfer(insts, tableName);
        });
    }

    /**
     * 新增客户订单
     * @param customerOrders
     */
    protected void insertCustomerOrders(List<CustomerOrder> customerOrders) {
        //ISaveHandler<CustomerOrder> saveHandler = SaveHandlerFactory.getSaveHandler(CustomerOrder.class);
        //saveHandler.insert(customerOrders, TableConsts.CustomerOrder.getTableName());
    }

    /**
     * 更新客户订单
     * @param customerOrders
     */
    protected void updateCustomerOrders(List<CustomerOrder> customerOrders) {
        ISaveHandler<CustomerOrder> saveHandler = SaveHandlerFactory.getSaveHandler(CustomerOrder.class);
        saveHandler.update(customerOrders, TableConsts.CustomerOrder.getTableName());
    }

    /**
     * 更新客户订单(update不为null的值)
     * @param customerOrders
     */
    protected void updateCustomerOrdersSelective(List<CustomerOrder> customerOrders) {
        ISaveHandler<CustomerOrder> saveHandler = SaveHandlerFactory.getSaveHandler(CustomerOrder.class);
        saveHandler.updateSelective(customerOrders, TableConsts.CustomerOrder.getTableName());
    }

    /**
     * 删除客户订单
     * @param customerOrders
     */
    protected void deleteCustomerOrders(List<CustomerOrder> customerOrders) {
        ISaveHandler<CustomerOrder> saveHandler = SaveHandlerFactory.getSaveHandler(CustomerOrder.class);
        saveHandler.delete(customerOrders, TableConsts.CustomerOrder.getTableName());
    }

    /**
     * 过户客户订单
     * @param customerOrders
     */
    protected void transferCustomerOrders(List<CustomerOrder> customerOrders) {
        ISaveHandler<CustomerOrder> saveHandler = SaveHandlerFactory.getSaveHandler(CustomerOrder.class);
        saveHandler.transfer(customerOrders, TableConsts.CustomerOrder.getTableName());
    }

    /**
     * 新增订单项
     * @param orderItems
     */
    protected void insertOrderItems(List<OrderItem> orderItems) {
        ISaveHandler<OrderItem> saveHandler = SaveHandlerFactory.getSaveHandler(OrderItem.class);
        saveHandler.insert(orderItems, TableConsts.OrderItem.getTableName());
    }

    /**
     * 新增订单项关系
     * @param orderItemRels
     */
    protected void insertOrderItemRels(List<OrderItemRel> orderItemRels) {
        ISaveHandler<OrderItemRel> saveHandler = SaveHandlerFactory.getSaveHandler(OrderItemRel.class);
        saveHandler.insert(orderItemRels, TableConsts.OrderItemRel.getTableName());
    }

    /**
     * 新增客户订单属性
     * @param orderAttrs
     */
    protected void insertOrderAttrs(List<OrderAttr> orderAttrs) {
        ISaveHandler<OrderAttr> saveHandler = SaveHandlerFactory.getSaveHandler(OrderAttr.class);
        saveHandler.insert(orderAttrs, TableConsts.OrderAttr.getTableName());
    }

    /**
     * 更新客户订单属性
     * @param orderAttrs
     */
    protected void updateOrderAttrs(List<OrderAttr> orderAttrs) {
        ISaveHandler<OrderAttr> saveHandler = SaveHandlerFactory.getSaveHandler(OrderAttr.class);
        saveHandler.update(orderAttrs, TableConsts.OrderAttr.getTableName());
    }

    /**
     * 删除客户订单属性
     * @param orderAttrs
     */
    protected void deleteOrderAttrs(List<OrderAttr> orderAttrs) {
        ISaveHandler<OrderAttr> saveHandler = SaveHandlerFactory.getSaveHandler(OrderAttr.class);
        saveHandler.delete(orderAttrs, TableConsts.OrderAttr.getTableName());
    }

    /**
     * 过户客户订单属性
     * @param orderAttrs
     */
    protected void transferOrderAttrs(List<OrderAttr> orderAttrs) {
        ISaveHandler<OrderAttr> saveHandler = SaveHandlerFactory.getSaveHandler(OrderAttr.class);
        saveHandler.transfer(orderAttrs, TableConsts.OrderAttr.getTableName());
    }

    /**
     * 新增订单经办人信息
     * @param orderHandlers
     */
    protected void insertOrderHandlers(List<OrderHandler> orderHandlers) {
        ISaveHandler<OrderHandler> saveHandler = SaveHandlerFactory.getSaveHandler(OrderHandler.class);
        saveHandler.insert(orderHandlers, TableConsts.OrderHandler.getTableName());
    }

    /**
     * 新增订单联系人信息
     * @param orderContactInfos
     */
    protected void insertOrderContactInfos(List<OrderContactInfo> orderContactInfos) {
        ISaveHandler<OrderContactInfo> saveHandler = SaveHandlerFactory.getSaveHandler(OrderContactInfo.class);
        saveHandler.insert(orderContactInfos, TableConsts.OrderContactInfo.getTableName());
    }

    /**
     * 新增订单项属性
     * @param orderItemAttrs
     */
    protected void insertOrderItemAttrs(List<OrderItemAttr> orderItemAttrs) {
        ISaveHandler<OrderItemAttr> saveHandler = SaveHandlerFactory.getSaveHandler(OrderItemAttr.class);
        saveHandler.insert(orderItemAttrs, TableConsts.OrderItemAttr.getTableName());
    }

    /**
     * 新增订单项变更记录
     * @param orderItemChanges
     */
    protected void insertOrderItemChanges(List<OrderItemChange> orderItemChanges) {
        ISaveHandler<OrderItemChange> saveHandler = SaveHandlerFactory.getSaveHandler(OrderItemChange.class);
        saveHandler.insert(orderItemChanges, TableConsts.OrderItemChange.getTableName());
    }

    /**
     * 新增订单项费用
     * @param acctItems
     */
    protected void insertAcctItems(List<AcctItemHis> acctItems) {
        ISaveHandler<AcctItemHis> saveHandler = SaveHandlerFactory.getSaveHandler(AcctItem.class);
        saveHandler.insert(acctItems, TableConsts.AcctItem.getTableName());
    }

    /**
     * 新增发展人(促销人)信息
     * @param devStaffInfos
     */
    protected void insertDevStaffInfos(List<DevStaffInfo> devStaffInfos) {
        ISaveHandler<DevStaffInfo> saveHandler = SaveHandlerFactory.getSaveHandler(DevStaffInfo.class);
        saveHandler.insert(devStaffInfos, TableConsts.DevStaffInfo.getTableName());
    }

    /**
     * 新增预存款信息
     * @param orderDeposits
     */
    protected void insertOrderDeposits(List<OrderDeposit> orderDeposits) {
        ISaveHandler<OrderDeposit> saveHandler = SaveHandlerFactory.getSaveHandler(OrderDeposit.class);
        saveHandler.insert(orderDeposits, TableConsts.OrderDeposit.getTableName());
    }
}
